package org.jtb.neoapi;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jtb.neodroid.R;

import android.graphics.Color;

public class Neo {
	public static String NEO_URL = "http://neo.jpl.nasa.gov";

	public static class DateComparator implements Comparator<Neo> {
		private boolean asc = true;

		public DateComparator(boolean asc) {
			this.asc = asc;
		}

		public int compare(Neo o1, Neo o2) {
			if (asc) {
				return o1.date.compareTo(o2.date);
			} else {
				return o2.date.compareTo(o1.date);
			}
		}
	}

	public static class SizeComparator implements Comparator<Neo> {
		private boolean asc = true;

		public SizeComparator(boolean asc) {
			this.asc = asc;
		}

		public int compare(Neo o1, Neo o2) {
			if (asc) {
				return Float.compare(o1.avgDiameter, o2.avgDiameter);
			} else {
				return Float.compare(o2.avgDiameter, o1.avgDiameter);
			}
		}
	}

	public static class DistanceComparator implements Comparator<Neo> {
		private boolean asc = true;

		public DistanceComparator(boolean asc) {
			this.asc = asc;
		}

		public int compare(Neo o1, Neo o2) {
			if (asc) {
				return Float.compare(o1.missDistanceAu, o2.missDistanceAu);
			} else {
				return Float.compare(o2.missDistanceAu, o1.missDistanceAu);
			}
		}
	}

	private static final Pattern FLOAT_PATTERN = Pattern.compile("([\\d\\.]+)");
	private static final Pattern UNITS_PATTERN = Pattern.compile("(k?m)");

	private static final DateFormat DATE_FORMAT = new SimpleDateFormat(
			"yyyy-MMM-dd");
	private static final DateFormat MONTH_FORMAT = new SimpleDateFormat("MMM");
	private static final DateFormat DAY_FORMAT = new SimpleDateFormat("d");
	private static final DateFormat YEAR_FORMAT = new SimpleDateFormat("yyyy");

	public static final HashMap<String, Comparator<Neo>> comparatorMap = new HashMap<String, Comparator<Neo>>();

	static {
		comparatorMap.put("date-asc", new DateComparator(true));
		comparatorMap.put("date-desc", new DateComparator(false));
		comparatorMap.put("size-asc", new SizeComparator(true));
		comparatorMap.put("size-desc", new SizeComparator(false));
		comparatorMap.put("distance-asc", new DistanceComparator(true));
		comparatorMap.put("distance-desc", new DistanceComparator(false));
	}

	private String name;
	private String url;
	private Date date;
	private float missDistanceAu;
	private float missDistanceLd;
	private float missDistanceMeters;
	private float missDistanceKm;
	private float missDistanceMiles;
	private float minDiameter;
	private float maxDiameter;
	private float avgDiameter;
	private float avgDiameterFeet;
	private float magnitude;
	private float velocity;
	private int color;
	private int imageId = -1;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	@Override
	public String toString() {
		return "{ name=" + name + ", url=" + url + ", date="
				+ DATE_FORMAT.format(date) + ", missDistanceAu="
				+ missDistanceAu + ", missDistanceLd=" + missDistanceLd
				+ ", diameter=" + minDiameter + "-" + maxDiameter
				+ ", magnitude=" + magnitude + ", velocity=" + velocity + " }";
	}

	public Date getDate() {
		return date;
	}

	public String getDateString() {
		return DATE_FORMAT.format(date);
	}

	public String getMonthString() {
		return MONTH_FORMAT.format(date);
	}

	public String getDayString() {
		return DAY_FORMAT.format(date);
	}

	public String getYearString() {
		return YEAR_FORMAT.format(date);
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public void setDate(String dateString) {
		try {
			date = DATE_FORMAT.parse(dateString);
		} catch (ParseException pe) {
			// TODO: log
			date = null;
		}
	}

	public float getMissDistanceAu() {
		return missDistanceAu;
	}

	public void setMissDistanceAu(float missDistanceAu) {
		this.missDistanceAu = missDistanceAu;
		this.missDistanceMeters = (float) (missDistanceAu * 149.6 * Math.pow(
				10, 9));
		this.missDistanceKm = missDistanceMeters / 1000;
		this.missDistanceMiles = (float) (missDistanceKm * 0.62137119);

		if (missDistanceMeters / 1000 < Math.pow(10, 6)) {
			color = Color.parseColor("#aaffdddd");
		} else if (missDistanceMeters / 1000 > Math.pow(10, 7)) {
			color = Color.parseColor("#aaddffdd");
		} else {
			color = Color.parseColor("#aaffffdd");
		}
	}

	public void setMissDistanceAu(String missDistanceAuString) {
		setMissDistanceAu(Float.parseFloat(missDistanceAuString));
	}

	public float getMissDistanceLd() {
		return missDistanceLd;
	}

	public void setMissDistanceLd(float missDistanceLd) {
		this.missDistanceLd = missDistanceLd;
	}

	public void setMissDistanceLd(String missDistanceLdString) {
		this.missDistanceLd = Float.parseFloat(missDistanceLdString);
	}

	public float getMagnitude() {
		return magnitude;
	}

	public void setMagnitude(float magnitude) {
		this.magnitude = magnitude;
	}

	public void setMagnitude(String magnitudeString) {
		this.magnitude = Float.parseFloat(magnitudeString);
	}

	public float getMinDiameter() {
		return minDiameter;
	}

	public void setMinDiameter(float minDiameter) {
		this.minDiameter = minDiameter;
	}

	public void setMinDiameter(String minDiameterString) {
		Matcher m = FLOAT_PATTERN.matcher(minDiameterString);
		if (m.find()) {
			this.minDiameter = Float.parseFloat(m.group(1));
		}
		m = UNITS_PATTERN.matcher(minDiameterString);
		if (m.find()) {
			if (m.group(1).equals("km")) {
				minDiameter *= 1000;
			}
		}
	}

	public float getMaxDiameter() {
		return maxDiameter;
	}

	public void setMaxDiameter(float maxDiameter) {
		this.maxDiameter = maxDiameter;
		avgDiameter = (maxDiameter + minDiameter) / 2;
		avgDiameterFeet = (float) (avgDiameter * 3.2808399);
	}

	public void setMaxDiameter(String maxDiameterString) {
		Matcher m = FLOAT_PATTERN.matcher(maxDiameterString);
		if (m.find()) {
			setMaxDiameter(Float.parseFloat(m.group(1)));
		}
		m = UNITS_PATTERN.matcher(maxDiameterString);
		if (m.find()) {
			if (m.group(1).equals("km")) {
				setMaxDiameter(maxDiameter * 1000);
			}
		}
	}

	public float getDiameterAverage() {
		return avgDiameter;
	}

	public float getVelocity() {
		return velocity;
	}

	public void setVelocity(float velocity) {
		this.velocity = velocity;
	}

	public void setVelocity(String velocityString) {
		this.velocity = Float.parseFloat(velocityString);
	}

	public float getMissDistanceKm() {
		return missDistanceKm;
	}

	public float getMissDistanceMiles() {
		return missDistanceMiles;
	}

	public int getColor() {
		return color;
	}

	public int getImageId() {
		if (imageId == -1) {
			float avg = getDiameterAverage();
			if (avg < 10) {
				imageId = R.drawable.asteroid_xsmall;
			} else if (avg < 100) {
				imageId = R.drawable.asteroid_small;
			} else if (avg < 1000) {
				imageId = R.drawable.asteroid_med;
			} else {
				imageId = R.drawable.asteroid_big;
			}
		}

		return imageId;
	}

	public float getDiameterAverageFeet() {
		return avgDiameterFeet;
	}
}
